/* Copyright (c) 2009, Michael Patraw
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * The name of Michael Patraw may not be used to endorse or promote
 *       products derived from this software without specific prior written
 *       permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Michael Patraw ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Michael Patraw BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "fps.h"

#include <stdbool.h>
#include <string.h>

#include "at.h"

#define _MAX_FRAMES 100

/* Array of the past 100 frames to keep a stable FPS timer.
 */
static double _frame_times[_MAX_FRAMES];
static int _size = 0;

bool _has_started = false;

static double _limit = 1000;

static int _frame_start = 0;

void Fps_Limit(double fps)
{
    _limit = fps;
}

void Fps_Start(void)
{
    if (!_has_started) {
        memset(_frame_times, 0, sizeof(_frame_times));
        _frame_start = atGetMili();
        _has_started = true;
    }
}

void Fps_BeginFrame(void)
{
    _frame_start = atGetMili();
}

double Fps_Get(void)
{
    int i;
    double avg = 0;
    
    for (i = 0; i < _size; ++i)
        avg += _frame_times[i];
    
    return avg / _size;
}

void Fps_EndFrame(void)
{
    if (atGetMili() - _frame_start == 0) {
        return;
    }
    
    while ((1000.0 / (atGetMili() - _frame_start)) > _limit)
        ;

    if (_size == _MAX_FRAMES) {
        memmove(_frame_times + 1, _frame_times, _MAX_FRAMES - 1);
        _frame_times[_MAX_FRAMES - 1] = 1000.0 / (atGetMili() - _frame_start);
    }
    else {
        _frame_times[_size] = 1000.0 / (atGetMili() - _frame_start);
        ++_size;
    }
    
    
}
